package com.rzx.mybackend.aop;
import com.rzx.mybackend.annotation.OrderIdempotent;
import com.rzx.mybackend.dto.BuyMerchandiseDTO;
import com.rzx.mybackend.utils.CommonUtils;
import com.rzx.mybackend.utils.RedissonUtil;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * MerchandiseOrderIdempotentAspect
 * 周边订单提交幂等性处理
 * @author renzhexian
 * @date 2025/8/15
 */
@Aspect
@Component
@RequiredArgsConstructor
public class MerchandiseOrderIdempotentAspect {

    private static final Logger log = LoggerFactory.getLogger(MerchandiseOrderIdempotentAspect.class);
    
    private final CommonUtils commonUtils;

    private final RedissonUtil redissonUtil;

    @Around("@annotation(idempotent)")
    public Object handleIdempotent(ProceedingJoinPoint joinPoint, OrderIdempotent idempotent) throws Throwable {
        log.info("MerchandiseOrderIdempotentAspect.handleIdempotent() - 进入幂等性处理");

        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            log.warn("方法参数为空，跳过幂等性检查");
            return joinPoint.proceed();
        }

        Object arg = args[0];
        if (!(arg instanceof List<?> argList)) {
            log.warn("方法参数不是List类型，跳过幂等性检查");
            return joinPoint.proceed();
        }

        // 校验泛型是否符合BuyMerchandiseDTO
        List<BuyMerchandiseDTO> validList = argList.stream()
                .filter(BuyMerchandiseDTO.class::isInstance)
                .map(BuyMerchandiseDTO.class::cast)
                .toList();

        // 如果存在非BuyMerchandiseDTO元素，跳过幂等性检查
        if (validList.size() != argList.size()) {
            log.warn("List中包含非BuyMerchandiseDTO元素，跳过幂等性检查");
            return joinPoint.proceed();
        }

        if (validList.isEmpty()) {
            log.warn("购买商品列表为空，跳过幂等性检查");
            return joinPoint.proceed();
        }

        // 进行幂等性校验
        String key = generateRedisKey(validList);

        // 判断是否重复提交
        if (!redissonUtil.tryLock(key, 0, 5, TimeUnit.SECONDS)) {
            log.warn("检测到重复提交，key: {}", key);
            throw new RuntimeException("请勿重复提交");
        }

        // 执行业务逻辑
        try {
            Object result = joinPoint.proceed();
            log.info("业务执行成功，即将释放锁");
            return result;
        } catch (Throwable e) {
            log.error("业务执行失败，key: {}", key, e);
            throw e;
        }
    }

    /**
     * 生成RedisKey
     * @param list
     * @return RedisKey
     */
    private String generateRedisKey(List<BuyMerchandiseDTO> list) {
        // 构造Redis键
        StringBuilder sb = new StringBuilder();
        list.stream()
            .sorted(Comparator.comparing(BuyMerchandiseDTO::getMerchandiseId))
            .forEach(dto -> sb.append(commonUtils.getCurrentUserId())
                    .append(dto.getMerchandiseId())
                    .append(":")
                    .append(dto.getBuyQuantity())
                    .append("|"));
        // 使用MD5处理key
        return "order:" + DigestUtils.md5DigestAsHex(sb.toString().getBytes());
    }
}
